//********************************************************************************************************
// Product Name: MapWindow.dll Alpha
// Description:  The basic module for MapWindow version 6.0
//********************************************************************************************************
// The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at 
// http://www.mozilla.org/MPL/ 
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 
// ANY KIND, either expressed or implied. See the License for the specificlanguage governing rights and 
// limitations under the License. 
//
// The Original Code is from MapWindow.dll version 6.0
//
// The Initial Developer of this Original Code is Ted Dunsford. Created 7/22/2008 11:26:38 AM
// 
// Contributor(s): (Open source contributors should list themselves and their modifications here). 
//
//********************************************************************************************************

using System;
using MapWindow.Geometries;
using Microsoft.DirectX;

namespace MapWindow.DirectX
{


    /// <summary>
    /// A DrawCube is like a 3D drawing window except that instead of working with geometries in 2 dimensions,
    /// it works in 3 dimensions.
    /// </summary>
    public class DrawBox : IDrawTransform
    {
        #region Private Variables

        

        private decimal _minX;
        private decimal _maxX;
        private decimal _minY;
        private decimal _maxY;
        private decimal _minZ;
        private decimal _maxZ;

        #endregion

       


        #region Constructors

        /// <summary>
        /// Creates a new instance of DrawCube
        /// </summary>
        public DrawBox()
        {
            
        }

        /// <summary>
        /// Creates a new instance of DrawCube with the specified extents.
        /// </summary>
        /// <param name="xMin"></param>
        /// <param name="xMax"></param>
        /// <param name="yMin"></param>
        /// <param name="yMax"></param>
        /// <param name="zMin"></param>
        /// <param name="zMax"></param>
        public DrawBox(decimal xMin, decimal xMax, decimal yMin, decimal yMax, decimal zMin, decimal zMax)
        {
            _minX = xMin;
            _maxX = xMax;
            _minY = yMin;
            _maxY = yMax;
            _minZ = zMin;
            _maxZ = zMax;
        }

        /// <summary>
        /// Creates a new instance of DrawCube with the specified extents.
        /// </summary>
        /// <param name="xMin"></param>
        /// <param name="xMax"></param>
        /// <param name="yMin"></param>
        /// <param name="yMax"></param>
        /// <param name="zMin"></param>
        /// <param name="zMax"></param>
        public DrawBox(double xMin, double xMax, double yMin, double yMax, double zMin, double zMax)
        {
            _minX = Convert.ToDecimal(xMin);
            _maxX = Convert.ToDecimal(xMax);
            if (_maxX <= _minX) _maxX = _minX + .0000000000001m;
            _minY = Convert.ToDecimal(yMin);
            _maxY = Convert.ToDecimal(yMax);
            if (_maxY <= _minY) _maxY = _minY + .0000000000001m;
            _minZ = Convert.ToDecimal(zMin);
            _maxZ = Convert.ToDecimal(zMax);
            if (_maxZ <= _minZ) _maxZ = _minZ + .0000000000001m;
        }

        
   

        #endregion

        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="db"></param>
        /// <returns></returns>
        public bool Equals(DrawBox db)
        {
            if (_minX == db.MinX && _maxX == db.MaxX &&
               _minY == db.MinY && _maxY == db.MaxY &&
               _minZ == db.MinZ && _maxZ == db.MaxZ) return true;
            return false;
        }

        /// <summary>
        /// Converts a decimal valued coordinate from some kind of projection space into a
        /// corresponding location in the 3D view.
        /// </summary>
        /// <param name="coord">Any valid Implementation of Coordinate.</param>
        /// <returns>A Vector3 representing the position in world coordinates.</returns>
        public virtual Vector3 ProjToView(Coordinate coord)
        {
            Vector temp = new Vector(coord); // remove NAN values
            decimal x, y, z;
            x = FloatToDecimal(temp.X);
            y = FloatToDecimal(temp.Y);
            z = FloatToDecimal(temp.Z);

            Vector3 result = new Vector3();
            result.X = Convert.ToSingle((x - _minX) / XSpan);
            result.Y = Convert.ToSingle((y - _minY) / YSpan);
            result.Z = -Convert.ToSingle(z / ZSpan);
            return result;
        }

        private decimal FloatToDecimal(double val)
        {
            decimal result = 0M;
            if (decimal.TryParse(val.ToString(), out result) == false)
            {
                if (val > (float)decimal.MaxValue)
                {
                    result = decimal.MaxValue;
                }
                else
                {
                    result = decimal.MinValue;
                }
            }
            return result;
        }

        /// <summary>
        /// Converts a decimal valued coordinate from some kind of projection space into a
        /// corresponding location in the 3D view.
        /// </summary>
        /// <param name="vect">Any valid Implementation of Vector.</param>
        /// <returns>A Vector3 representing the position in world coordinates.</returns>
        public virtual Vector3 ProjToView(Vector vect)
        {
            Vector3 result = new Vector3();
            decimal longitude = decimal.Parse(vect.X.ToString());
            decimal x = (longitude - _minX) / XSpan;
            result.X = Convert.ToSingle(x);
            result.Y = Convert.ToSingle((decimal.Parse(vect.Y.ToString()) - _minY) / YSpan);
            result.Z = -Convert.ToSingle(Convert.ToDecimal(vect.Z) / ZSpan);
            return result;
        }

        /// <summary>
        /// Transforms a value from the 3D model space into the equivalent, decimal precision
        /// floating coordinate domain.
        /// </summary>
        /// <param name="position">The 3D position in model space to turn into geographic coordinates</param>
        /// <returns>The geographic coordinates to display.</returns>
        public virtual Coordinate ViewToProj(Vector3 position)
        {
            // 1
            decimal pX = Convert.ToDecimal(position.X);
            decimal pY = Convert.ToDecimal(position.Y);
            decimal pZ = -Convert.ToDecimal(position.Z);
           

       
            decimal x = pX * XSpan + _minX;


            //System.Diagnostics.Debug.WriteLine("tempMin: " + tempMin.ToString() + ", tempSpan: " + tempSpan.ToString() + ", temp: " + temp.ToString() + ", tempDouble: " + tempDouble.ToString() + ", dX: " + dX.ToString() + " X: " + x.ToString());
            decimal y = pY * YSpan + _minY;
            decimal z = pZ * ZSpan;
            Coordinate c = new Coordinate(double.Parse(x.ToString()), double.Parse(y.ToString()), double.Parse(z.ToString()));
           // System.Diagnostics.Debug.WriteLine("minX: " + _minX + ", dX: " + dX + " X: " + x);
            return c;
        }

        /// <summary>
        /// Gets the 3D multiplicative conversion scale from 
        /// </summary>
        /// <returns></returns>
        public virtual Vector GetScale()
        {
            Vector result = new Vector();
            result.X = Convert.ToDouble(XSpan);
            result.Y = Convert.ToDouble(YSpan);
            result.Z = Convert.ToDouble(ZSpan);
            return result;
        }

        /// <summary>
        /// Transforms a value form the 3D model space into a vector with the X, Y and Z terms
        /// that would match the geographic location.
        /// </summary>
        /// <param name="position">The position in model space</param>
        /// <returns>An Vector in geographic coordinates</returns>
        public virtual Vector ViewToProjVector(Vector3 position)
        {
            decimal pX = Convert.ToDecimal(position.X);
            decimal pY = Convert.ToDecimal(position.Y);
            decimal pZ = -Convert.ToDecimal(position.Z);

            decimal x = pX * XSpan + _minX;
            decimal y = pY * YSpan + _minY;
            decimal z = pZ * ZSpan;
            Vector v = new Vector(double.Parse(x.ToString()), double.Parse(y.ToString()), double.Parse(z.ToString()));
            return v;
        }
        

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the minimum geographic value in the x direction of the cube,
        /// which is described as 0 in cube coordinates
        /// </summary>
        public virtual decimal MinX
        {
            get { return _minX; }
            set { _minX = value; }
        }

        /// <summary>
        /// Gets or sets the maximum geographic value in the x direction of the cube,
        /// which is described as 1 in cube coordinates
        /// </summary>
        public virtual decimal MaxX
        {
            get { return _maxX; }
            set { _maxX = value; }
        }

        /// <summary>
        /// Gets or sets the minimum geographic value in the y direction of the cube,
        /// which is described as 0 in cube coordinates
        /// </summary>
        public virtual decimal MinY
        {
            get { return _minY; }
            set { _minY = value; }
        }

        /// <summary>
        /// Gets or sets the maximum geographic value in the y direction of the cube,
        /// which is described as 1 in cube coordinates
        /// </summary>
        public virtual decimal MaxY
        {
            get { return _maxY; }
            set { _maxY = value; }
        }


        /// <summary>
        /// Gets or sets the minimum geographic value in the z direction of the cube,
        /// which is described as 0 in cube coordinates
        /// </summary>
        public virtual decimal MinZ
        {
            get { return _minZ; }
            set { _minZ = value; }
        }

        /// <summary>
        /// Gets or sets the maximum geographic value in the z direction of the cube,
        /// which is described as 1 in cube coordinates
        /// </summary>
        public virtual decimal MaxZ
        {
            get { return _maxZ; }
            set { _maxZ = value; }
        }

        /// <summary>
        /// The difference between the maximum and minimum X values.
        /// </summary>
        public virtual decimal XSpan
        {
            get { return Math.Abs(_maxX - _minX); }
        }

        /// <summary>
        /// The difference between the maximum and minimum Y values.
        /// </summary>
        public virtual decimal YSpan
        {
            get { return Math.Abs(_maxY - MinY); }
        }

        /// <summary>
        /// The difference between the maximum and minimum Z values.
        /// </summary>
        public virtual decimal ZSpan
        {
            get { return Math.Abs(_maxZ = MinZ); }
        }

        #endregion



    }
}
